package main

import (
	"bytes"
	b "code.google.com/p/gochess/board"
	"code.google.com/p/gochess/notation/fen"
	"code.google.com/p/gochess/notation/lan"
	pos "code.google.com/p/gochess/position"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"sort"
	"strings"
)

var (
	start    *pos.Position
	rootPath string
)

func setup(path string) {
	rootPath = path
	info := ReadValues(rootPath)
	var err error

	// first row contains "fen=<FEN STRING>\n"
	start, err = fen.Parse(string(info[bytes.Index(info, []byte("="))+1 : bytes.Index(info, []byte("\n"))]))
	if err != nil {
		panic(err)
	}

}

func handler(w http.ResponseWriter, r *http.Request) {

	currentPosition := *start
	values := r.URL.Query()
	fmt.Fprintf(w, "<h1>%s - %s</h1>", values.Get("id"), strings.Join(values["path"], "/"))

	// update position with move path
	var moveLan, dummy string
	for i := 0; i < len(values["path"]); i++ {
		l, err := fmt.Sscan(values["path"][i], &dummy, &moveLan)
		if l != 2 {
			panic(fmt.Sprintf("l is %d, must be 2, err is: %v", l, err))
		}
		if err != nil {
			panic(err)
		}
		move, err := lan.ParseMove(&currentPosition, moveLan)
		if err != nil {
			panic(fmt.Sprintf("%s - %s", values["path"][i], err))
		}
		pos.MakeMove(&currentPosition, move)
	}

	fmt.Fprint(w, "<h2>Position</h2>")
	RenderPosition(w, &currentPosition)
	fmt.Fprintf(w, "%s<br>", fen.Sprint(&currentPosition))
	fmt.Fprintf(w, "Side to move: %s<br>", currentPosition.SideToMove())
	id := values.Get("id")
	path := values["path"]
	logPath := rootPath

	if len(id) != 0 {
		logPath += "/" + id
		if len(values["path"]) > 0 {
			logPath += "/" + strings.Join(values["path"], "/")
		}
	}

	fmt.Fprint(w, "<h2>Properties</h2>")
	fmt.Fprint(w, string(bytes.Replace(ReadValues(logPath), []byte("\n"), []byte("<br>\n"), -1)))

	f, err := os.Open(logPath)
	if err != nil {
		panic(err)
	}
	directories, err := f.Readdirnames(-1)
	if err != nil {
		panic(err)
	}
	sort.Strings(directories)
	fmt.Fprint(w, "<h2>Moves</h2>")
	// directory move ordering, first entriy comes last
	for i := 0; i < len(directories); i++ {
		move := directories[i]
		if string(move) == "info" {
			continue
		}
		if len(id) == 0 {
			values.Set("id", move)
		} else {
			values["path"] = append(path, move)
		}
		fmt.Fprintf(w, "<a href=/?%s>%s</a> ", values.Encode(), move)
	}
}

func main() {

	port := flag.Uint("p", 8080, "port the server is listen")

	flag.Usage = Usage
	flag.Parse()
	if flag.NArg() == 0 {
		Usage()
	}

	setup(flag.Arg(0))
	http.HandleFunc("/", handler)
	http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
}

var bg = [2]string{
	0: "white",
	1: "#cccccc",
}

var Pieces = map[pos.Piece]string{

	pos.WhiteKing:   "&#9812;",
	pos.WhiteQueen:  "&#9813;",
	pos.WhiteRook:   "&#9814;",
	pos.WhiteBishop: "&#9815;",
	pos.WhiteKnight: "&#9816;",
	pos.WhitePawn:   "&#9817;",

	pos.BlackKing:   "&#9818;",
	pos.BlackQueen:  "&#9819;",
	pos.BlackRook:   "&#9820;",
	pos.BlackPawn:   "&#9821;",
	pos.BlackKnight: "&#9822;",
	pos.BlackBishop: "&#9823;",

	pos.NoPiece: "&nbsp;",
}

func ReadValues(path string) []byte {
	data, err := ioutil.ReadFile(path + "/info")
	if err != nil {
		panic(err)
	}
	return data
}

func RenderPosition(w io.Writer, position *pos.Position) {

	fmt.Fprintf(w, `<table cellpadding="0" cellspacing="0" border="1">`+"\n")
	c := 0
	for rank := b.Rank8; rank >= b.Rank1; rank-- {
		fmt.Fprintf(w, "<tr>\n")
		for file := b.A; file <= b.H; file++ {
			square := b.GetSquare(file, b.Rank(rank))
			fmt.Fprintf(w, "<td style=\"font-size: 130%%; background-color:%s; width:%s;\">%s</td>",
				bg[c], "12.5%", Pieces[position.Get(square)])
			c ^= 1
		}
		c ^= 1
		fmt.Fprintf(w, "<tr>\n")
	}
	fmt.Fprintf(w, "</table>\n")
}

func Usage() {
	fmt.Fprintf(os.Stderr, "usage: %s [-p port] directory\n", os.Args[0])
	fmt.Fprintf(os.Stderr, "\twhere directory contains the search tree\n")
	os.Exit(2)
}
